/*
 * Created on 07.12.2003
 */
package observations;

/**
 <code>Quantity</code> Represents a value such as 6 feet or 5 $. It's part
 * of Fowler's pattern 'Quantity'.
 
 @author Sascha Hemminger
 @version 2004-09-10
 */
public class Quantity {
  private double amount;

  private Unit unit;

  /**
   * Basic constructor used by all other constructors.
   
   @param amount
   *            numeric value of the quantity
   @param unit
   *            the unit (eg. $)
   */
  public Quantity(double amount, Unit unit) {
    requireNonNull(unit);
    this.amount = amount;
    this.unit = unit;
  }

  /**
   * Same as basic constructor, but value given as integer.
   
   @param amount
   *            numeric integer value
   @param unit
   *            the unit (eg. $)
   @see #Quantity(double, Unit)
   */
  public Quantity(int amount, Unit unit) {
    this(new Double(amount).doubleValue(), unit);
  }

  /**
   * Parses the given string and calls basic constructor.
   
   @param amountString
   *            string representation of a numeric value
   @param unit
   *            the unit (eg. $)
   @see #Quantity(double, Unit)
   */
  public Quantity(String amountString, Unit unit) {
    this(new Double(amountString).doubleValue(), unit);
  }

  /**
   * Tests if this quantity equals the argument (this == arg).
   
   @param arg
   *            other quantity
   @return true if both quantities equal
   */
  public boolean equals(Quantity arg) {
    return unit.equals(arg.getUnit()) && (amount == arg.getAmount());
  }

  /**
   * Get the quantity's numeric value.
   
   @return numeric value
   */
  public double getAmount() {
    return amount;
  }

  /**
   * Gives a string representation of the quantity's value.
   
   @return value as a string
   */
  public String getAmountString() {
    return String.valueOf(amount);
  }

  /**
   * Get this quantity's unit.
   
   @return the unit
   */
  public Unit getUnit() {
    return unit;
  }

  /**
   * Tests if this quantity is greater than argument (this > arg).
   
   @param arg
   *            other quantity
   @return true if this is greater than argument
   */
  public boolean isGreaterThan(Quantity arg) {
    requireSameUnitsAs(arg);
    return !isLessThanOrEqualTo(arg);
  }

  /**
   * Tests if this quantity is greater than or equal to argument (this >=
   * arg).
   
   @param arg
   *            other quantity
   @return true if this is greater than or equal to argument
   */
  public boolean isGreaterThanOrEqualTo(Quantity arg) {
    requireSameUnitsAs(arg);
    return !isLessThan(arg);
  }

  /**
   * Tests if this quantity is less than the argument (this < arg).
   
   @param arg
   *            other quantity
   @return true if this is less than argument
   */
  public boolean isLessThan(Quantity arg) {
    requireSameUnitsAs(arg);
    return amount < arg.getAmount();
  }

  /**
   * Tests if this quantity is less than or equal to argument (this <= arg).
   
   @param arg
   *            other quantity
   @return true if this is less than or equal to argument
   */
  public boolean isLessThanOrEqualTo(Quantity arg) {
    requireSameUnitsAs(arg);
    return isLessThan(arg|| equals(arg);
  }

  protected void requireNonNull(Object arg) {
    if (arg == null)
      throw new NullPointerException();
  }

  private void requireSameUnitsAs(Quantity arg) {
    if (!unit.equals(arg.getUnit()))
      throw new IllegalArgumentException();
  }

}